﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace Gmantis.Controls.DataGrid
{
    [TemplatePart(Name = "FirstBound", Type = typeof(NumericBox)), 
    TemplatePart(Name = "OrRadioButton", Type = typeof(RadioButton)), 
    TemplatePart(Name = "NoneRadioButton", Type = typeof(RadioButton)), 
    TemplatePart(Name = "AndRadioButton", Type = typeof(RadioButton)), 
    TemplatePart(Name = "SecondComparator", Type = typeof(ComboBox)), 
    TemplatePart(Name = "FirstComparator", Type = typeof(ComboBox)), 
    TemplatePart(Name = "SecondBound", Type = typeof(NumericBox))]
    public class DataGridNumericFilter : Control, IDataGridFilter, IDataGridFilterUnity, INotifyPropertyChanged
    {
        // Fields
        private DataGridFilterCombination _combination;
        internal RadioButton _elementAndRadioButton;
        internal NumericBox _elementFirstBound;
        internal ComboBox _elementFirstComparator;
        internal RadioButton _elementNoneRadioButton;
        internal RadioButton _elementOrRadioButton;
        internal NumericBox _elementSecondBound;
        internal ComboBox _elementSecondComparator;
        private DataGridFilterState _filter;
        private DataGridFilterOperation _firstComparator = DataGridFilterOperation.Equal;
        private double _firstValue;
        internal bool _isLoaded;
        private List<NumericComparator> _itemsSource;
        private DataGridFilterOperation _secondComparator = DataGridFilterOperation.Equal;
        private double _secondValue;
        internal const string AndRadioButtonElementName = "AndRadioButton";
        internal const string FirstBoundElementName = "FirstBound";
        internal const string FirstComparatorElementName = "FirstComparator";
        public static readonly DependencyProperty FocusBrushProperty = DependencyProperty.Register("FocusBrush", typeof(Brush), typeof(DataGridNumericFilter), null);
        public static readonly DependencyProperty InputBackgroundProperty = DependencyProperty.Register("InputBackground", typeof(Brush), typeof(DataGridNumericFilter), null);
        public static readonly DependencyProperty InputForegroundProperty = DependencyProperty.Register("InputForeground", typeof(Brush), typeof(DataGridNumericFilter), null);
        public static readonly DependencyProperty MouseOverBrushProperty = DependencyProperty.Register("MouseOverBrush", typeof(Brush), typeof(DataGridNumericFilter), null);
        internal const string NoneRadioButtonElementName = "NoneRadioButton";
        internal const string OrRadioButtonElementName = "OrRadioButton";
        public static readonly DependencyProperty PressedBrushProperty = DependencyProperty.Register("PressedBrush", typeof(Brush), typeof(DataGridNumericFilter), null);
        internal const string SecondBoundElementName = "SecondBound";
        internal const string SecondComparatorElementName = "SecondComparator";
        public static readonly DependencyProperty SelectedBackgroundProperty = DependencyProperty.Register("SelectedBackground", typeof(Brush), typeof(DataGridNumericFilter), null);

        // Events
        public event EventHandler<PropertyChangedEventArgs<DataGridFilterState>> FilterChanged;

        public event PropertyChangedEventHandler PropertyChanged;

        // Methods
        public DataGridNumericFilter()
        {
            base.DefaultStyleKey = typeof(DataGridNumericFilter);
        }

        private void ApplyFilterState(DataGridFilterInfo filterInfo, bool firstLine)
        {
            if (firstLine)
            {
                this._firstComparator = filterInfo.FilterOperation;
                this._firstValue = Convert.ToDouble(filterInfo.Value);
            }
            else
            {
                this._combination = filterInfo.FilterCombination;
                this._secondComparator = filterInfo.FilterOperation;
                this._secondValue = Convert.ToDouble(filterInfo.Value);
            }
        }

        private void ApplyState(DataGridFilterState filterState)
        {
            if ((((filterState != null) && (filterState.FilterInfo != null)) && ((filterState.FilterInfo.Count > 0) && (filterState.FilterInfo[0] != null))) && (filterState.FilterInfo[0].FilterType == DataGridFilterType.Numeric))
            {
                if ((filterState.FilterInfo.Count > 0) && (filterState.FilterInfo[0] != null))
                {
                    this.ApplyFilterState(filterState.FilterInfo[0], true);
                }
                if ((filterState.FilterInfo.Count > 1) && (filterState.FilterInfo[1] != null))
                {
                    this.ApplyFilterState(filterState.FilterInfo[1], false);
                }
            }
            else
            {
                this._firstComparator = DataGridFilterOperation.Equal;
                this._firstValue = 0.0;
                this._combination = DataGridFilterCombination.None;
                this._secondComparator = DataGridFilterOperation.Equal;
                this._secondValue = 0.0;
                this._filter = null;
            }
            this.RaisePropertyChanged("FirstComparator");
            this.RaisePropertyChanged("FirstValue");
            this.RaisePropertyChanged("Combination");
            this.RaisePropertyChanged("SecondComparator");
            this.RaisePropertyChanged("SecondValue");
            this.RaisePropertyChanged("Filter");
        }

        public void Clear()
        {
            DataGridFilterState state3;
            DataGridFilterState state = this._filter;
            this.Filter = (DataGridFilterState)(state3 = null);
            DataGridFilterState state2 = state3;
            if (this.FilterChanged != null)
            {
                PropertyChangedEventArgs<DataGridFilterState> e = new PropertyChangedEventArgs<DataGridFilterState>
                {
                    OldValue = state,
                    NewValue = state2
                };
                this.FilterChanged(this, e);
            }
        }

        public void Create()
        {
            if (this._isLoaded)
            {
                DataGridFilterState state = this._filter;
                DataGridFilterState filter = this.GetFilter();
                this._filter = filter;
                if (this.FilterChanged != null)
                {
                    PropertyChangedEventArgs<DataGridFilterState> e = new PropertyChangedEventArgs<DataGridFilterState>
                    {
                        OldValue = state,
                        NewValue = filter
                    };
                    this.FilterChanged(this, e);
                }
            }
        }

        private DataGridFilterState GetFilter()
        {
            List<DataGridFilterInfo> list = new List<DataGridFilterInfo>(2);
            DataGridFilterInfo filterInfo = this.GetFilterInfo(this.FirstValue, this.FirstComparator);
            list.Add(filterInfo);
            if (this.Combination != DataGridFilterCombination.None)
            {
                DataGridFilterInfo item = this.GetFilterInfo(this.SecondValue, this.SecondComparator);
                item.FilterCombination = this.Combination;
                list.Add(item);
            }
            return new DataGridFilterState { FilterInfo = list };
        }

        private DataGridFilterInfo GetFilterInfo(double value, DataGridFilterOperation operation)
        {
            return new DataGridFilterInfo { Value = value, FilterType = DataGridFilterType.Numeric, FilterOperation = operation };
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        public void Load(DataGridFilterState filterState)
        {
            this.ApplyState(filterState);
        }

        private void OnAfterApplyTemplate()
        {
            this._itemsSource = new List<NumericComparator>(6);
            this._itemsSource.Add(new NumericComparator(DataGridFilterOperation.Equal, "Equals"));
            this._itemsSource.Add(new NumericComparator(DataGridFilterOperation.GreaterThan, "Greater"));
            this._itemsSource.Add(new NumericComparator(DataGridFilterOperation.GreaterThanOrEqual, "Greater/Equals"));
            this._itemsSource.Add(new NumericComparator(DataGridFilterOperation.LessThan, "Less"));
            this._itemsSource.Add(new NumericComparator(DataGridFilterOperation.LessThanOrEqual, "Less/Equals"));
            this._itemsSource.Add(new NumericComparator(DataGridFilterOperation.NotEqual, "Not Equals"));
            this._elementFirstComparator.DisplayMemberPath = "ComparisonSymbol";
            this._elementFirstComparator.SelectedValuePath = "Comparison";
            this._elementFirstComparator.ItemsSource = this._itemsSource;
            Binding binding = new Binding
            {
                Mode = BindingMode.TwoWay
            };
            this._elementFirstComparator.SetBinding(ComboBox.SelectedValueProperty, binding.From<DataGridNumericFilter>(this, x => x.FirstComparator));
            this._elementSecondComparator.DisplayMemberPath = "ComparisonSymbol";
            this._elementSecondComparator.SelectedValuePath = "Comparison";
            this._elementSecondComparator.ItemsSource = this._itemsSource;
            Binding binding2 = new Binding
            {
                Mode = BindingMode.TwoWay
            };
            this._elementSecondComparator.SetBinding(ComboBox.SelectedValueProperty, binding2.From<DataGridNumericFilter>(this, x => x.SecondComparator));
            Binding binding3 = new Binding
            {
                Converter = CustomConverter.Create((value, type, parameter, culture) => ((DataGridFilterCombination)value) != DataGridFilterCombination.None)
            };
            this._elementSecondComparator.SetBinding(Control.IsEnabledProperty, binding3.From<DataGridNumericFilter>(this, x => x.Combination));
            Binding binding4 = new Binding
            {
                Mode = BindingMode.TwoWay
            };
            this._elementFirstBound.SetBinding(NumericBox.ValueProperty, binding4.From<DataGridNumericFilter>(this, x => x.FirstValue));
            Binding binding5 = new Binding
            {
                Mode = BindingMode.TwoWay
            };
            this._elementSecondBound.SetBinding(NumericBox.ValueProperty, binding5.From<DataGridNumericFilter>(this, x => x.SecondValue));
            Binding binding6 = new Binding
            {
                Converter = CustomConverter.Create((value, type, parameter, culture) => ((DataGridFilterCombination)value) != DataGridFilterCombination.None)
            };
            this._elementSecondBound.SetBinding(Control.IsEnabledProperty, binding6.From<DataGridNumericFilter>(this, x => x.Combination));
            this._elementNoneRadioButton.GroupName = "NoneGroup";
            Binding binding7 = new Binding
            {
                Mode = BindingMode.TwoWay,
                Converter = CustomConverter.Create((value, type, parameter, culture) => ((DataGridFilterCombination)value) == DataGridFilterCombination.None, (value, type, parameter, culture) => DataGridFilterCombination.None)
            };
            this._elementNoneRadioButton.SetBinding(ToggleButton.IsCheckedProperty, binding7.From<DataGridNumericFilter>(this, x => x.Combination));
            this._elementOrRadioButton.GroupName = "OrGroup";
            Binding binding8 = new Binding
            {
                Mode = BindingMode.TwoWay,
                Converter = CustomConverter.Create((value, type, parameter, culture) => ((DataGridFilterCombination)value) == DataGridFilterCombination.Or, (value, type, parameter, culture) => DataGridFilterCombination.Or)
            };
            this._elementOrRadioButton.SetBinding(ToggleButton.IsCheckedProperty, binding8.From<DataGridNumericFilter>(this, x => x.Combination));
            this._elementAndRadioButton.GroupName = "AndGroup";
            Binding binding9 = new Binding
            {
                Mode = BindingMode.TwoWay,
                Converter = CustomConverter.Create((value, type, parameter, culture) => ((DataGridFilterCombination)value) == DataGridFilterCombination.And, (value, type, parameter, culture) => DataGridFilterCombination.And)
            };
            this._elementAndRadioButton.SetBinding(ToggleButton.IsCheckedProperty, binding9.From<DataGridNumericFilter>(this, x => x.Combination));
            try
            {
                this._elementFirstBound.Format = this.Format ?? "";
            }
            catch
            {
                this._elementFirstBound.Format = "";
            }
            try
            {
                this._elementSecondBound.Format = this.Format ?? "";
            }
            catch
            {
                this._elementSecondBound.Format = "";
            }
        }

        public override void OnApplyTemplate()
        {
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._isLoaded = true;
            this._elementFirstComparator = this.GetTemplateChild<ComboBox>("FirstComparator", true, ref errors);
            this._elementSecondComparator = this.GetTemplateChild<ComboBox>("SecondComparator", true, ref errors);
            this._elementFirstBound = this.GetTemplateChild<NumericBox>("FirstBound", true, ref errors);
            this._elementSecondBound = this.GetTemplateChild<NumericBox>("SecondBound", true, ref errors);
            this._elementOrRadioButton = this.GetTemplateChild<RadioButton>("OrRadioButton", true, ref errors);
            this._elementAndRadioButton = this.GetTemplateChild<RadioButton>("AndRadioButton", true, ref errors);
            this._elementNoneRadioButton = this.GetTemplateChild<RadioButton>("NoneRadioButton", true, ref errors);
            if (!string.IsNullOrEmpty(errors))
            {
                this._isLoaded = false;
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to DataGridNumericFilter.\nDetails: {0}", new object[] { errors }));
                }
            }
            else
            {
                this.OnAfterApplyTemplate();
            }
        }

        protected void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        // Properties
        public DataGridFilterCombination Combination
        {
            get
            {
                return this._combination;
            }
            set
            {
                this._combination = value;
                this._filter = this.GetFilter();
                this.RaisePropertyChanged("Combination");
                this.RaisePropertyChanged("Filter");
            }
        }

        public DataGridFilterState Filter
        {
            get
            {
                return this._filter;
            }
            set
            {
                if (this._filter != value)
                {
                    this._filter = value;
                    this.ApplyState(this._filter);
                }
            }
        }

        public DataGridFilterOperation FirstComparator
        {
            get
            {
                return this._firstComparator;
            }
            set
            {
                this._firstComparator = value;
                this._filter = this.GetFilter();
                this.RaisePropertyChanged("FirstComparator");
                this.RaisePropertyChanged("Filter");
            }
        }

        public double FirstValue
        {
            get
            {
                return this._firstValue;
            }
            set
            {
                this._firstValue = value;
                this._filter = this.GetFilter();
                this.RaisePropertyChanged("FirstValue");
                this.RaisePropertyChanged("Filter");
            }
        }

        public Brush FocusBrush
        {
            get
            {
                return (Brush)base.GetValue(FocusBrushProperty);
            }
            set
            {
                base.SetValue(FocusBrushProperty, value);
            }
        }

        public string Format { get; set; }

        public Brush InputBackground
        {
            get
            {
                return (Brush)base.GetValue(InputBackgroundProperty);
            }
            set
            {
                base.SetValue(InputBackgroundProperty, value);
            }
        }

        public Brush InputForeground
        {
            get
            {
                return (Brush)base.GetValue(InputForegroundProperty);
            }
            set
            {
                base.SetValue(InputForegroundProperty, value);
            }
        }

        public Brush MouseOverBrush
        {
            get
            {
                return (Brush)base.GetValue(MouseOverBrushProperty);
            }
            set
            {
                base.SetValue(MouseOverBrushProperty, value);
            }
        }

        public Brush PressedBrush
        {
            get
            {
                return (Brush)base.GetValue(PressedBrushProperty);
            }
            set
            {
                base.SetValue(PressedBrushProperty, value);
            }
        }

        public DataGridFilterOperation SecondComparator
        {
            get
            {
                return this._secondComparator;
            }
            set
            {
                this._secondComparator = value;
                this._filter = this.GetFilter();
                this.RaisePropertyChanged("SecondComparator");
                this.RaisePropertyChanged("Filter");
            }
        }

        public double SecondValue
        {
            get
            {
                return this._secondValue;
            }
            set
            {
                this._secondValue = value;
                this._filter = this.GetFilter();
                this.RaisePropertyChanged("SecondValue");
                this.RaisePropertyChanged("Filter");
            }
        }

        public Brush SelectedBackground
        {
            get
            {
                return (Brush)base.GetValue(SelectedBackgroundProperty);
            }
            set
            {
                base.SetValue(SelectedBackgroundProperty, value);
            }
        }
    }
}
